/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package top.defaults.colorpicker;

import ohos.agp.utils.Color;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import top.defaults.colorpicker.util.NumCalcUtil;

import java.math.BigDecimal;

/**
 * 颜色转换工具类
 *
 * @author: ColorPicker
 * @since 2021-04-16
 */
public final class ColorConverUtils {
    private static final int LOGID = 0x000115;
    private static final float ALPHA = 255f;
    private static final int ADJUSTCOLOR = 0x00ffffff;
    private static final int ONE = -1;
    private static final int SECOND = 2;
    private static final int THIRD = 3;
    private static final int FOUR = 4;
    private static final int FIVE = 5;
    private static final int SIX = 6;
    private static final int NUMBER8 = 8;
    private static final int NUMBER16 = 16;
    private static final int ADJUST = 24;
    private static final int SIXTEN = 60;
    private static final int ONWSECOND = 120;
    private static final int SECONDFOUR = 240;
    private static final int ALPHAINT = 255;
    private static final int THIRDSIX = 360;
    private static final int WHITE = 0xFFFFFFFF;
    private static final int WHITE2 = 0xFFFFFF;
    private static final int TOUMING = 0xff0000;
    private static HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, LOGID, "Utils");

    private ColorConverUtils() {
    }

    /**
     * 透明度数值
     *
     * @param argb
     * @return 透明度数值
     */
    public static float getAlphaPercent(int argb) {
        return Color.alpha(argb) / ALPHA;
    }

    /**
     * 透明度数值
     *
     * @param alpha
     * @return 透明度数值
     */
    public static int alphaValueAsInt(float alpha) {
        return Math.round(alpha * ALPHAINT);
    }

    /**
     * 透明度调整
     *
     * @param alpha
     * @param color
     * @return 透明度数值
     */
    public static int adjustAlpha(float alpha, int color) {
        return alphaValueAsInt(alpha) << ADJUST | (ADJUSTCOLOR & color);
    }

    /**
     * colorAtLightness
     *
     * @param color
     * @param lightness
     * @return colorAtLightness
     */
    public static int colorAtLightness(int color, float lightness) {
        double[] hsv = new double[THIRD];

        // color id 转RGB
        int red = (color & Constants.DEFAULT) >> NUMBER16;
        int green = (color & Constants.DEFAULT2) >> NUMBER8;
        int blue = color & Constants.DEFAULT3;
        double[] hsvColor = rgbToHsv(red, green, blue);
        hsv[0] = (float) hsvColor[0];
        hsv[1] = (float) hsvColor[1];
        hsv[SECOND] = (float) hsvColor[SECOND];
        hsv[SECOND] = lightness;
        double[] rgbColor = hsb2rgb(hsv);
        int colorinit = Color.rgb((int) rgbColor[0], (int) rgbColor[1], (int) rgbColor[SECOND]);
        return colorinit;
    }

    /**
     * 获取颜色亮度数值
     *
     * @param color
     * @return 获取颜色亮度数值
     */
    public static float lightnessOfColor(int color) {
        int red = (color & Constants.DEFAULT) >> NUMBER16;
        int green = (color & Constants.DEFAULT2) >> NUMBER8;
        int blue = color & Constants.DEFAULT3;
        double[] hsvColor = rgbToHsv(red, green, blue);
        return (float) hsvColor[SECOND];
    }

    /**
     * 颜色id和透明度转Hex格式
     *
     * @param color
     * @param isShowAlpha
     * @return 颜色id和透明度转Hex格式
     */
    public static String isHexString(int color, boolean isShowAlpha) {
        int isBase = isShowAlpha ? WHITE : WHITE2;
        String format = isShowAlpha ? "#%08X" : "#%06X";
        return String.format(format, isBase & color);
    }

    /**
     * 颜色id转Hex格式
     *
     * @param color
     * @return 颜色id转Hex格式
     */
    public static String getHexString(int color) {
        String her = Integer.toHexString(color);
        return her;
    }

    /**
     * HSV转RGB
     *
     * @param hsvHcolor
     * @param hsvScolor
     * @param hsvVcolor
     * @return rgb色值
     */
    public static int[] hsvToRgb(double hsvHcolor, double hsvScolor, double hsvVcolor) {
        int[] colors = new int[THIRD];
        double index =  Math.floor(hsvHcolor * SIX);
        double floadValue = hsvHcolor * SIX - index;
        float presentValue = (float)(hsvVcolor * (1 - hsvScolor));
        float qq = (float) (hsvVcolor * (1 - floadValue * hsvScolor));
        float tt = (float) (hsvVcolor * (1 - (1 - floadValue) * hsvScolor));
        double rgbr = 0;
        double rgbg = 0;
        double rgbb = 0;
        switch ((int) (index % SIX)) {
            case 0:
                rgbr = hsvVcolor;
                rgbg = tt;
                rgbb = presentValue;
                break;
            case 1:
                rgbr = qq;
                rgbg = hsvVcolor;
                rgbb = presentValue;
                break;
            case SECOND:
                rgbr = presentValue;
                rgbg = hsvVcolor;
                rgbb = tt;
                break;
            case THIRD:
                rgbr = presentValue;
                rgbg = qq;
                rgbb = hsvVcolor;
                break;
            case FOUR:
                rgbr = tt;
                rgbg = presentValue;
                rgbb = hsvVcolor;
                break;
            case FIVE:
                rgbr = hsvVcolor;
                rgbg = presentValue;
                rgbb = qq;
                break;
            default:
        }
        colors[0] = (int) Math.floor(rgbr * ALPHAINT);
        colors[1] = (int) Math.floor(rgbg * ALPHAINT);
        colors[SECOND] = (int) Math.floor(rgbb * ALPHAINT);
        return colors;
    }

    /**
     * rgb转hsv
     *
     * @param rr
     * @param gg
     * @param bb
     * @return rgb转hsv
     */
    public static double[] rgbToHsv(double rr, double gg, double bb) {
        double hh;
        double ss;
        double vv;
        double min;
        double max;
        min = Math.min(Math.min(rr, gg), bb);
        max = Math.max(Math.max(rr, gg), bb);
        double delta;
        vv = max;
        delta = max - min;
        if (max != 0) {
            ss = delta / max;
        } else {
            ss = 0;
            hh = ONE;
            return new double[]{hh, ss, vv};
        }

        // H
        if (rr == max) {
            hh = (gg - bb) / delta; // between yellow & magenta
        } else if (gg == max) {
            hh = SECOND + (bb - rr) / delta; // between cyan & yellow
        } else {
            hh = FOUR + (rr - gg) / delta; // between magenta & cyan
        }
        hh *= SIXTEN; // degrees
        if (hh < 0) {
            hh += THIRDSIX;
        }
        return new double[]{hh, ss, vv};
    }

    /**
     * 颜色id转rgb
     *
     * @param color
     * @return 颜色id转rgb
     */
    public static int[] colorToRgb(int color) {
        // color id 转RGB
        int red = (color & Constants.DEFAULT) >> NUMBER16;
        int green = (color & Constants.DEFAULT2) >> NUMBER8;
        int blue = color & Constants.DEFAULT3;
        return new int[]{red, green, blue};
    }

    /**
     * hsv格式颜色转rgb格式
     *
     * @param hsb
     * @return hsv格式颜色转rgb格式
     */
    public static double[] hsb2rgb(double[] hsb) {
        double[] rgb = new double[THIRD];

        // 先令饱和度和亮度为100%，调节色相h
        for (int offset = SECONDFOUR, inum = 0; inum < THIRD; inum++, offset -= ONWSECOND) {
            // 算出色相h的值和三个区域中心点(即0°，120°和240°)相差多少，然后根据坐标图按分段函数算出rgb。
            // 但因为色环展开后，红色区域的中心点是0°同时也是360°，不好算，索性将三个区域的中心点都向右平移到240°再计算比较方便
            double xx = Math.abs((hsb[0] + offset) % THIRDSIX - SECONDFOUR);

            // 如果相差小于60°则为255
            if (xx <= SIXTEN) {
                rgb[inum] = ALPHAINT;
            }

            // 如果相差在60°和120°之间，
            else if (xx > SIXTEN && xx < ONWSECOND) {
                rgb[inum] = (1 - (xx - SIXTEN) / SIXTEN) * ALPHAINT;
            }

            // 如果相差大于120°则为0
            else {
                rgb[inum] = 0;
            }
        }

        // 在调节饱和度s
        for (int ii = 0; ii < THIRD; ii++) {
            rgb[ii] += NumCalcUtil.multiply(NumCalcUtil.subtract(ALPHAINT, (float) rgb[ii]), NumCalcUtil.subtract(1, (float) hsb[1]));
        }

        // 最后调节亮度b
        for (int ii = 0; ii < THIRD; ii++) {
            rgb[ii] *= hsb[SECOND];
        }
        return rgb;
    }

    /**
     * hex转rgb
     *
     * @param hex
     * @return hex转rgb
     */
    public static int[] hexToRgb(String hex) {
        int color = Integer.parseInt(hex.replace("#", ""), NUMBER16);
        int red = (color & Constants.DEFAULT) >> NUMBER16;
        int green = (color & Constants.DEFAULT2) >> NUMBER8;
        int blue = color & Constants.DEFAULT3;
        return new int[]{red, green, blue};
    }

    /**
     * hex转color
     *
     * @param hex
     * @return hex转color
     */
    public static int hexToColor(String hex) {
        int color = Integer.parseInt(hex.replace("#", ""), NUMBER16);
        return color;
    }
}
